Skip to content

Fix N+1 query pattern in bulk pool delete endpoint#66222

Merged
jason810496 merged 4 commits into
apache:mainfrom
ColtenOuO:fix-bulk-pool-delete-n-plus-one
May 18, 2026
Merged

Fix N+1 query pattern in bulk pool delete endpoint#66222
jason810496 merged 4 commits into
apache:mainfrom
ColtenOuO:fix-bulk-pool-delete-n-plus-one

Conversation

@ColtenOuO
Copy link
Copy Markdown
Contributor

@ColtenOuO ColtenOuO commented May 1, 2026

Summary

Eliminates an N+1 query in the bulk pool delete endpoint by reusing the ORM objects already loaded by BulkPoolService.categorize_pools() instead of re-fetching each pool one at a time inside the delete loop.

Why

categorize_pools() already loads every requested pool with a single batched SELECT ... WHERE pool IN (...) and returns them as existing_pools_dict: dict[str, Pool]. handle_bulk_delete() was discarding that dict (_, matched, not_found = ...) and then re-querying each pool individually inside the loop:

for pool_name in delete_pool_names:
    existing_pool = self.session.scalar(select(Pool).where(Pool.pool == pool_name).limit(1))
    ...

For a request that deletes N pools, this produced 2N + 1 round-trips to the database (1 batched SELECT in categorize_pools + N redundant per-pool SELECTs + N DELETEs). The redundant per-pool SELECTs return objects we already have in memory.

Change 1

Behavior is preserved exactly: existing_pools_dict.get(pool_name) returns the same Pool instance the per-pool SELECT would have returned (it's the same object loaded by categorize_pools in the same session), and is None when the pool doesn't exist — matching the original session.scalar(...).limit(1) semantics.

Change 2

Added a unit test that asserts the expected query count.

Impact

Bulk size Before (queries) After (queries) Saved
10 pools 21 11 -48%
100 pools 201 101 -50%

Unit Test Results

To ensure this optimization doesn't introduce any regressions, I've verified the changes with the existing test suite. All tests passed.

Command:
uv run --project airflow-core pytest airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py::TestBulkPools -x

Was generative AI tooling used to co-author this PR?

Yes — (Claude Sonnet 4.6, for test_bulk_delete_does_not_re_query_each_pool in airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py‎)

Copy link
Copy Markdown
Contributor

@SameerMesiah97 SameerMesiah97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid performance improvement.

@ColtenOuO
Copy link
Copy Markdown
Contributor Author

I’ve noted that handle_bulk_update and update_orm_from_pydantic in pools.py likely suffer from similar N+1 query issues. I've intentionally kept this PR focused to verify if this optimization approach aligns with the project's expectations.

Once this logic is confirmed and merged, I will follow up with another PR to address the remaining functions. Thanks again to all the reviewers!

Copy link
Copy Markdown
Member

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, thanks for the improvement.
It would be nice to add or edit corresponding test case to guard the query count.

FYI, the assert_queries_count is the current convention to check the expected query count.

def test_get_dags(self, test_client, query_params, expected_total_entries, expected_ids, session):
# Only create asset test data for asset-related tests to avoid affecting other tests
if any(param in query_params for param in ["has_asset_schedule", "asset_dependency"]):
self._create_asset_test_data(session)
with assert_queries_count(4):
response = test_client.get("/dags", params=query_params)
assert response.status_code == 200
body = response.json()
assert body["total_entries"] == expected_total_entries
actual_ids = [dag["dag_id"] for dag in body["dags"]]
assert actual_ids == expected_ids

@ColtenOuO
Copy link
Copy Markdown
Contributor Author

Thanks for the suggestion @jason810496 — I've added a test that uses assert_queries_count per the convention you linked.

Additionally, while checking this unit test, I realized that using round-trip times provides a more accurate evaluation of the impact. I have updated the table below to reflect this:

Bulk size Before After Saved
10 pools 14 4 −71%
100 pools 104 4 −96%

If you have any feedback or suggestions for this PR, feel free to let me know! Thanks to all the reviewers for your support!

Copy link
Copy Markdown
Contributor

@henry3260 henry3260 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your effort!

Comment thread airflow-core/src/airflow/api_fastapi/core_api/services/public/pools.py Outdated
@ColtenOuO ColtenOuO force-pushed the fix-bulk-pool-delete-n-plus-one branch from f7055e7 to 1a6ae94 Compare May 3, 2026 11:31
@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label May 5, 2026
@ColtenOuO ColtenOuO requested a review from henry3260 May 15, 2026 17:29
Copy link
Copy Markdown
Contributor

@henry3260 henry3260 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think we are almost there

Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py Outdated
@eladkal eladkal added this to the Airflow 3.2.2 milestone May 16, 2026
@eladkal eladkal added type:bug-fix Changelog: Bug Fixes backport-to-v3-2-test Mark PR with this label to backport to v3-2-test branch labels May 16, 2026
@ColtenOuO ColtenOuO force-pushed the fix-bulk-pool-delete-n-plus-one branch from 1a6ae94 to 6ded2bf Compare May 17, 2026 08:04
Copy link
Copy Markdown
Member

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, one final nit before merge. Thanks.

Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py Outdated
Copy link
Copy Markdown
Member

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to simplify as accepting single pool_count? Since the expected count should be the same.

Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py Outdated
Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py Outdated
Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_pools.py Outdated
@ColtenOuO
Copy link
Copy Markdown
Contributor Author

Thanks for the feedback @jason810496!

Refactored the code based on your suggestion. I initially over-engineered it to avoid the hardcoded query count.

Feel free to let me know if there’s anything else or if I misunderstood anything.

@ColtenOuO ColtenOuO requested a review from jason810496 May 17, 2026 17:56
@ColtenOuO ColtenOuO force-pushed the fix-bulk-pool-delete-n-plus-one branch from 7a4cc2d to 69fc441 Compare May 17, 2026 18:42
@ColtenOuO
Copy link
Copy Markdown
Contributor Author

Fixed ruff formatting to pass CI (force-pushed to the latest commit).

@potiuk
Copy link
Copy Markdown
Member

potiuk commented May 18, 2026

@ColtenOuO — There are 4 unresolved review threads on this PR from @jason810496. Could you either push a fix or reply in each thread explaining why the feedback doesn't apply? Once you believe the feedback is addressed, mark the thread as resolved so the reviewer isn't re-pinged needlessly. Thanks!


Note: This comment was drafted by an AI-assisted triage tool and may contain mistakes. Once you have addressed the points above, an Apache Airflow maintainer — a real person — will take the next look at your PR. We use this two-stage triage process so that our maintainers' limited time is spent where it matters most: the conversation with you.

@jason810496
Copy link
Copy Markdown
Member

Thanks for the fix.

@jason810496 jason810496 merged commit 91806fd into apache:main May 18, 2026
143 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

Backport successfully created: v3-2-test

Note: As of Merging PRs targeted for Airflow 3.X
the committer who merges the PR is responsible for backporting the PRs that are bug fixes (generally speaking) to the maintenance branches.

In matter of doubt please ask in #release-management Slack channel.

Status Branch Result
v3-2-test PR Link

vatsrahul1001 pushed a commit that referenced this pull request May 18, 2026
… (#67108)

* Fix N+1 query pattern in bulk pool delete endpoint

* Add query-count test for bulk pool delete

* Refactor bulk-delete query-count test to parametrize

* Parametrize bulk-delete query-count test by pool size
(cherry picked from commit 91806fd)

Co-authored-by: Colten <jun930436@gmail.com>
vatsrahul1001 pushed a commit that referenced this pull request May 20, 2026
… (#67108)

* Fix N+1 query pattern in bulk pool delete endpoint

* Add query-count test for bulk pool delete

* Refactor bulk-delete query-count test to parametrize

* Parametrize bulk-delete query-count test by pool size
(cherry picked from commit 91806fd)

Co-authored-by: Colten <jun930436@gmail.com>
vatsrahul1001 pushed a commit that referenced this pull request May 20, 2026
… (#67108)

* Fix N+1 query pattern in bulk pool delete endpoint

* Add query-count test for bulk pool delete

* Refactor bulk-delete query-count test to parametrize

* Parametrize bulk-delete query-count test by pool size
(cherry picked from commit 91806fd)

Co-authored-by: Colten <jun930436@gmail.com>
vatsrahul1001 pushed a commit that referenced this pull request May 21, 2026
… (#67108)

* Fix N+1 query pattern in bulk pool delete endpoint

* Add query-count test for bulk pool delete

* Refactor bulk-delete query-count test to parametrize

* Parametrize bulk-delete query-count test by pool size
(cherry picked from commit 91806fd)

Co-authored-by: Colten <jun930436@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:API Airflow's REST/HTTP API backport-to-v3-2-test Mark PR with this label to backport to v3-2-test branch ready for maintainer review Set after triaging when all criteria pass. type:bug-fix Changelog: Bug Fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants